import { API_BASE, API_TIMEOUT } from '@/config'
//import { gotoLogin } from '@/router'
import { waitPromise } from '@/utils'
import { create, HttpConfig } from '@/utils/http'
import { HttpRequestConfig, HttpResponse } from '@/utils/http/types'
import { HttpError } from '@/utils/http/utils'
import { refreshTokenApi } from '@/api/auth'
import { closeAllMessageBox, showAlert, showMessage } from '@/utils/ui'
import isPlainObject from 'lodash-es/isPlainObject'
import { clearToken, getToken, setToken } from '@/utils/auth'


export interface ApiRequestConfig extends HttpRequestConfig {
  /** 是否附加 Token，默认 true */
  authRequired?: boolean
  /** 是否忽略错误，正常返回 */
  ignoreError?: boolean
  /** 返回原始结果 */
  noExtract?: boolean

  /** UI 提示类型，默认 alert */
  showError?: 'alert' | 'toast' | false

  ___last___?: boolean
}

export interface RawResp<T> {
  code: number
  data: T
  msg: string
}

export interface Sort {
  key: string
  sort: 'asc' | 'desc' | '' | undefined
}

export interface PageParams {
  page: number
  size: number
  sort?: Sort
}

export interface PageData<T> extends Array<T> {
  total: number
}

const showingError = new Set<string>()
const showError = (msg?: string, type: 'alert' | 'toast' = 'alert') => {
  msg = msg || '未知错误'

  if (type === 'alert') {
    if (showingError.has(msg!)) return
    showingError.add(msg!)
    showAlert(
      {
        type: 'error',
        message: msg,
        beforeClose: (_a: any, _i: any, done: () => void) => {
          showingError.delete(msg!)
          done()
        },
      },
      '提示'
    )
  } else {
    showMessage({ type: 'error', message: msg })
  }
}

let notLoginShowing = false
const handleNotLogin = () => {
  if (notLoginShowing) return
  closeAllMessageBox()
  notLoginShowing = true
  showAlert({
    title: '提示',
    message: '登录已过期，请重新登录',
    type: 'warning',
    showCancelButton: false,
    closeOnClickModal: false,
    closeOnPressEscape: false,
    showClose: false,
    callback: () => {
      clearToken()
      //gotoLogin()
      notLoginShowing = false
    },
  })
}

const refreshToken = waitPromise(async (): Promise<any> => {
  const token = getToken()
  if (!token || !token.refreshToken) return
  try {
    const resp = await refreshTokenApi(token.refreshToken)
    setToken({
      tokenType: resp.accessToken.tokenType?.value,
      accessToken: resp.accessToken.tokenValue,
      refreshToken: resp.refreshToken.tokenValue,
    })
    return resp
  } catch {
    clearToken()
  }
})

const commonExtractData = (
  resp: HttpResponse<any, ApiRequestConfig>
): PromiseValue<any> => {
  let data = resp.data
  if (data instanceof Blob) return data
  if (!isApiResultData(data)) return data

  data = data.data
  if (data && typeof data === 'object') {
    if (data.total !== undefined && Array.isArray(data.records)) {
      data.records.total = data.total
      return data.records
    }
  }
  return data
}

const isApiResultData = (data: any) =>
  isPlainObject(data) && typeof data.code !== 'undefined'

export const createApi = (config: HttpConfig) => {
  return create<ApiRequestConfig>(
    config,
    (req) => {
      if (req.params?.$page) {
        const page = req.params.$page as PageParams
        delete req.params.$page
        Object.assign(req.params, {
          pageNum: page.page,
          pageSize: page.size,
          sortBy: page.sort?.key,
          sortType: page.sort?.sort,
        })
      }
      const headers = (req.headers = req.headers ?? {})

      if (req.authRequired !== false) {
        const token = getToken()
        if (token) {
          headers['Authorization'] =
            (token.tokenType ?? '') +
            (token.tokenType ? ' ' : '') +
            token.accessToken
        }
      }
      return req
    },
    async (req, e, resp) => {
      if (!resp || e) {
        showError(e?.message)
        throw e
      }
      let data = resp.data

      if (data instanceof Blob) {
        if (data.size < 2048 && data.type.includes('application/json')) {
          // 可能是错误信息
          try {
            const parsed = JSON.parse(await data.text())
            if (isApiResultData(parsed)) {
              data = parsed
            }
          } catch {
            // ignore
          }
        }
      }

      if (
        (resp.status === 401 || data?.code === 401) &&
        req.authRequired !== false
      ) {
        // 登录过期
        // 首先尝试刷新令牌
        if (await refreshToken()) {
          if (!req.___last___ && req._initiator) {
            // 刷新令牌后，重试
            return req._initiator.request({ ...req, ___last___: true })
          }
        }
        handleNotLogin()
        throw new HttpError('', resp, false)
      }

      if (resp.status !== 200 && !isApiResultData(resp.data)) {
        let msg: string
        if (resp.status === 403) msg = '无权限访问，请联系管理员'
        else msg = '请求失败: ' + resp.status

        if (req.showError !== false) showError(msg, req.showError)
        throw new HttpError(msg, resp, false)
      }

      const doExtra = req.noExtract ? (d: any) => d : commonExtractData

      if (isApiResultData(data) && data.code !== 200) {
        if (req.showError !== false) showError(data.msg, req.showError)
        if (req.ignoreError) return doExtra(resp)
        throw new HttpError(data.msg, resp, false)
      }
      if (e) throw e

      return doExtra(resp!)
    }
  )
}

export default createApi({ baseURL: API_BASE, timeout: API_TIMEOUT })
